package com.ruoyi.jt808.service.handler;

import cn.hutool.core.codec.BCD;
import cn.hutool.core.util.ArrayUtil;
import com.ruoyi.common.constant.CacheConstants;
import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.config.ApplicationContextHolder;
import com.ruoyi.jt808.common.TPMSConsts;
import com.ruoyi.jt808.server.SessionManager;
import com.ruoyi.jt808.service.TerminalMsgProcessService;
import com.ruoyi.jt808.service.codec.MsgDecoder;
import com.ruoyi.jt808.util.BitOperatorUtils;
import com.ruoyi.jt808.util.JT808ProtocolUtils;
import com.ruoyi.jt808.vo.PackageData;
import com.ruoyi.jt808.vo.req.LocationInfoUploadMsg;
import com.ruoyi.jt808.vo.req.TerminalAuthenticationMsg;
import com.ruoyi.jt808.vo.req.TerminalRegisterMsg;

import com.ruoyi.work.domain.TbLocationTrain;
import com.ruoyi.work.service.ITbLocationTrainService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.math.BigDecimal;

@Slf4j
@Component
public class MessageHandler {

    private ITbLocationTrainService trainService;

    private final SessionManager sessionManager;
    private final MsgDecoder msgDecoder;
    private final TerminalMsgProcessService msgProcessService;
    private final RedisCache redisCache;

    public MessageHandler() {
        this.sessionManager = SessionManager.getInstance();
        this.msgDecoder = new MsgDecoder();
        this.msgProcessService = new TerminalMsgProcessService();
        this.trainService = ApplicationContextHolder.getBean(ITbLocationTrainService.class);
        this.redisCache = ApplicationContextHolder.getBean(RedisCache.class);
    }

    
    public PackageData commonAnalysis(byte[] bs) {
        PackageData packageData = new PackageData();
        PackageData.MsgHeader msgHeader = new PackageData.MsgHeader();
        // 消息ID
        msgHeader.setMsgId(BitOperatorUtils.byteToInteger(ArrayUtil.sub(bs, 0, 2)));
        // 消息体属性(WORD)
        msgHeader.setHeaderMsgAttribute(BitOperatorUtils.byteToInteger(ArrayUtil.sub(bs, 2, 4)));
        // 以下运算如果看不懂，请复习位操作相关姿势
        // 消息体长度 [0-9] 0000,0011,1111,1111(0x1FF)
        msgHeader.setMsgBodyLength(msgHeader.getMsgBodyLength() & 0x1FF);
        // 消息加密方式[10] 1110,0000,0000(0xE00)
        msgHeader.setEncryptionType((msgHeader.getHeaderMsgAttribute() & 0xE00) >> 10);
        // 是否分包[13] 0010,0000,0000,0000(0x2000)
        msgHeader.setHasSubPackage(((msgHeader.getHeaderMsgAttribute() & 0x2000) >> 13) == 1);
        // 终端手机号(终端唯一标识)
        msgHeader.setTerminalPhone(BCD.bcdToStr(ArrayUtil.sub(bs, 4, 10)));
        // 消息流水号
        msgHeader.setFlowId(BitOperatorUtils.byteToInteger(ArrayUtil.sub(bs, 10, 12)));
        int bodyIndex = 12;
        if (msgHeader.isHasSubPackage()) {
            // 消息包总数
            msgHeader.setTotalSubPackage(BitOperatorUtils.byteToInteger(ArrayUtil.sub(bs, 12, 14)));
            // 消息包序号
            msgHeader.setSubPackageSeq(BitOperatorUtils.byteToInteger(ArrayUtil.sub(bs, 14, 16)));
            bodyIndex = 16;
        }
        packageData.setMsgHeader(msgHeader);
        if (msgHeader.getMsgBodyLength() > 0) {
            // 包体
            packageData.setMsgBodyBytes(ArrayUtil.sub(bs, bodyIndex, bs.length - 1));
        }
        // 校验码
        packageData.setCheckByte(ArrayUtil.sub(bs, bs.length - 1, bs.length));

        int checkSum = bs[bs.length - 1];
        int calcCheckSum = BitOperatorUtils.getCheckSumJt808(bs, 0, bs.length - 1);

        packageData.setCheckSum(checkSum);
        packageData.setFullMsgBytes(ArrayUtil.addAll(new byte[] {0x7e}, bs, new byte[] {0x7e}));

        if (checkSum != calcCheckSum) {
            log.warn("校验码不一致,命令ID:{},数据包中校验码:{},计算的校验码为:{}", Integer.toHexString(packageData.getMainSign()), checkSum,
                    calcCheckSum);
            packageData.setValid(false);
        }
        return packageData;
    }


    /**
     *
     * 处理业务逻辑
     *
     * @param packageData
     *
     */
    public void processPackageData(PackageData packageData) {
        final PackageData.MsgHeader header = packageData.getMsgHeader();

        // 1. 终端心跳-消息体为空 ==> 平台通用应答
        if (TPMSConsts.msg_id_terminal_heart_beat == header.getMsgId()) {
            log.info(">>>>>[终端心跳],phone={},flowid={}", header.getTerminalPhone(), header.getFlowId());
            try {
                this.msgProcessService.processTerminalHeartBeatMsg(packageData);
                log.info("<<<<<[终端心跳],phone={},flowid={}", header.getTerminalPhone(), header.getFlowId());
                redisCache.setCacheObject(CacheConstants.JT808_HART+packageData.getMsgHeader().getTerminalPhone(),1);
            } catch (Exception e) {
                log.error("<<<<<[终端心跳]处理错误,phone={},flowid={},err={}", header.getTerminalPhone(), header.getFlowId(),
                        e.getMessage());
                e.printStackTrace();
            }
        }

        // 5. 终端鉴权 ==> 平台通用应答
        else if (TPMSConsts.msg_id_terminal_authentication == header.getMsgId()) {
            log.info(">>>>>[终端鉴权],phone={},flowid={}", header.getTerminalPhone(), header.getFlowId());
            try {
                TerminalAuthenticationMsg authenticationMsg = new TerminalAuthenticationMsg(packageData);
                this.msgProcessService.processAuthMsg(authenticationMsg);
                log.info("<<<<<[终端鉴权],phone={},flowid={}", header.getTerminalPhone(), header.getFlowId());
            } catch (Exception e) {
                log.error("<<<<<[终端鉴权]处理错误,phone={},flowid={},err={}", header.getTerminalPhone(), header.getFlowId(),
                        e.getMessage());
                e.printStackTrace();
            }
        }
        // 6. 终端注册 ==> 终端注册应答
        else if (TPMSConsts.msg_id_terminal_register == header.getMsgId()) {
            log.info(">>>>>[终端注册],phone={},flowid={}", header.getTerminalPhone(), header.getFlowId());
            try {
                TerminalRegisterMsg msg = this.msgDecoder.toTerminalRegisterMsg(packageData);
                this.msgProcessService.processRegisterMsg(msg);
                redisCache.setCacheObject(CacheConstants.JT808_HART+packageData.getMsgHeader().getTerminalPhone(),1);
                log.info("<<<<<[终端注册],phone={},flowid={}", header.getTerminalPhone(), header.getFlowId());
            } catch (Exception e) {
                log.error("<<<<<[终端注册]处理错误,phone={},flowid={},err={}", header.getTerminalPhone(), header.getFlowId(),
                        e.getMessage());
                e.printStackTrace();
            }
        }
        // 7. 终端注销(终端注销数据消息体为空) ==> 平台通用应答
        else if (TPMSConsts.msg_id_terminal_log_out == header.getMsgId()) {
            log.info(">>>>>[终端注销],phone={},flowid={}", header.getTerminalPhone(), header.getFlowId());
            try {
                this.msgProcessService.processTerminalLogoutMsg(packageData);
                log.info("<<<<<[终端注销],phone={},flowid={}", header.getTerminalPhone(), header.getFlowId());
            } catch (Exception e) {
                log.error("<<<<<[终端注销]处理错误,phone={},flowid={},err={}", header.getTerminalPhone(), header.getFlowId(),
                        e.getMessage());
                e.printStackTrace();
            }
        }
        // 3. 位置信息汇报 ==> 平台通用应答
        else if (TPMSConsts.msg_id_terminal_location_info_upload == header.getMsgId()) {
            log.info(">>>>>[位置信息],phone={},flowid={}", header.getTerminalPhone(), header.getFlowId());
            try {
                LocationInfoUploadMsg locationInfoUploadMsg = this.msgDecoder.toLocationInfoUploadMsg(packageData);
                System.out.println(locationInfoUploadMsg);
                this.msgProcessService.processLocationInfoUploadMsg(locationInfoUploadMsg);
        
                TbLocationTrain locatinTrain = new TbLocationTrain();
                locatinTrain.setLastTime(locationInfoUploadMsg.getTime());
                locatinTrain.setLatitude(Double.toString(locationInfoUploadMsg.getLatitude()));
                locatinTrain.setLongitude(Double.toString(locationInfoUploadMsg.getLongitude()));
                locatinTrain.setTerminaPhone(locationInfoUploadMsg.getMsgHeader().getTerminalPhone());
                locatinTrain.setMsgId(locationInfoUploadMsg.getMsgHeader().getMsgId());
                locatinTrain.setDirection(locationInfoUploadMsg.getDirection());
                locatinTrain.setSpeed(BigDecimal.valueOf(locationInfoUploadMsg.getSpeed()));
                locatinTrain.setElevation(locationInfoUploadMsg.getElevation()+"");
                locatinTrain.setWarningFlagField(locationInfoUploadMsg.getWarningFlagField()+"");
                locatinTrain.setStatusField(locationInfoUploadMsg.getStatusField()+"");
                locatinTrain.setElectricity(locationInfoUploadMsg.getElectricity());
                trainService.insertTbLocationTrain(locatinTrain);

                log.info("<<<<<[位置信息],phone={},flowid={}", header.getTerminalPhone(), header.getFlowId());
            } catch (Exception e) {
                log.error("<<<<<[位置信息]处理错误,phone={},flowid={},err={}", header.getTerminalPhone(), header.getFlowId(),
                        e.getMessage());
                e.printStackTrace();
            }
        }
        // 其他情况
        else {
            log.error(">>>>>>[未知消息类型],phone={},msgId={},package={}", header.getTerminalPhone(), header.getMsgId(),
                    packageData);
        }
    }
}
